<?php
namespace EasyVote\EasyVoteBundle\Repository;

use Doctrine\ORM\EntityRepository;
use EasyVote\EasyVoteBundle\Entity\User;
use EasyVote\EasyVoteBundle\Entity\Profile;
use KULeuven\ShibbolethBundle\Security\ShibbolethUserProviderInterface;
use KULeuven\ShibbolethBundle\Security\ShibbolethUserToken;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;

/**
 * Class UserRepository
 * Stores the users in a database.
 * @package EasyVote\EasyVoteBundle\Repository
 */
class UserRepository extends EntityRepository implements ShibbolethUserProviderInterface
{
    /**
     * {@inheritDoc}
     */
    public function loadUserByUsername($username)
    {
        //To keep all of the users up to date, all user loading is done in CreateUser.
        throw new UsernameNotFoundException('');
    }

    /**
     * A simple function that takes care of adding multivalued attributes to a user.
     * @var ShibbolethUserToken $token
     * @var User $user The user
     * @var string $attributeNameInToken the name of the attribute as it will appear in the shibboleth user token
     * @var string $attributeNameInUser the name of the attribute as it will appear in the User class
     * @var string $attributeClassName the name of the class of the attribute
     * @var string $attributeField the field within the attribute's class to set.
     */
    private function addMultivaluedAttributeToUser(ShibbolethUserToken $token, User $user,
                                                   $attributeNameInToken, $attributeNameInUser,
                                                   $attributeClassName, $attributeField)
    {

        $em = $this->getEntityManager();

        //step 1: get the attribute and the storage repository
        $tokenXs = $token->getArrayAttribute($attributeNameInToken);
        $xRepo = $em->getRepository($attributeClassName);

        //step 2: iterate over token values
        foreach ($tokenXs as $tokenX) {
            //find in repo
            $mthd = 'findOneBy' . $attributeField;
            $currentX = $xRepo->$mthd($tokenX);

            //if it exists, add to user
            if ($currentX) {
                $mthd = 'add' . $attributeNameInUser;
                $user->$mthd($currentX);
            } //otherwise, create
            else {
                $currentX = new $attributeClassName();
                $mthd = 'set' . $attributeField;
                $currentX->$mthd($tokenX);
                $em->persist($currentX);
                $em->flush();

                //add to user
                $mthd = 'add' . $attributeNameInUser;
                $user->$mthd($currentX);
            }
        }
    }

    /**
     * Creates or loads a user that has logged in.
     * @param ShibbolethUserToken $token The user's token
     * @return User The user created/loaded.
     */
    public function createUser(ShibbolethUserToken $token)
    {
        $em = $this->getEntityManager();

        //Check for existing user
        $user = $this->findOneByEuid($token->getAttribute('euid'));
        if ($user == null) {
            //create a user if null and fill in the details
            $user = new User();
            $user->setEuid($token->getAttribute('euid'));
            $user->setEmployeeNumber($token->getAttribute('employeeNumber'));
            $user->setPrincipalName($token->getAttribute('principalName'));
            $user->setDisplayName('Default Display Name');

            //Add role. By default, everyone gets ROLE_USER.
            $rolesRepo = $em->getRepository('EasyVote\EasyVoteBundle\Entity\Role');
            $user->addRole($rolesRepo->findOneByValue('ROLE_USER'));
            $em->persist($user);
            $em->flush();

        }

        //Create multivalued attributes
        $this->addMultivaluedAttributeToUser($token, $user, 'mail', 'Email', 'EasyVote\EasyVoteBundle\Entity\Email', 'value');
        $this->addMultivaluedAttributeToUser($token, $user, 'affiliation', 'Affiliation', 'EasyVote\EasyVoteBundle\Entity\Affiliation', 'name');
        $this->addMultivaluedAttributeToUser($token, $user, 'scopedAffiliation', 'ScopedAffiliation', 'EasyVote\EasyVoteBundle\Entity\ScopedAffiliation', 'value');
        $em->persist($user);
        $em->flush();

        //Add a profile for the user.
        $profile = $user->getProfile();
        if ($profile == null) {
            $profile = new Profile();
            $profile->setPicture("http://placehold.it/200x200");
            $profile->setSummary("Default Summary");
            $profile->setText("Default Text");
            $profile->setTitle("Default Title");
            $profile->setUser($user);
            $user->setProfile($profile);
            $em->persist($profile);
            $em->flush();
        }
        return $user;
    }

    /**
     * Refreshes a user
     * @param UserInterface $user
     * @return UserInterface|void
     */
    public function refreshUser(UserInterface $user)
    {
        if (!$user instanceof User) {
            throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
        }
        return $this->loadUserByUsername($user->getUsername());
    }

    /**
     * Determines if the class of user is supported.
     * @param string $class
     * @return bool
     */
    public function supportsClass($class)
    {
        return $class === 'EasyVote\EasyVoteBundle\Entity\User';
    }

    /**
     * Checks if the user has edited his/her profile fully.
     * @param $profile The profile to check
     * @return bool True if edited; otherwise false.
     */
    public static function isProfileComplete($profile){
        if(!$profile->getPicture() || $profile->getPicture() == 'http://placehold.it/200x200'){
            return false;
        }
        else if(!$profile->getSummary() || $profile->getSummary() == "Default Summary"){
            return false;
        }
        else if(!$profile->getText() || $profile->getText() == "Default Text"){
            return false;
        }
        else if(!$profile->getTitle() || $profile->getTitle() == "Default Title"){
            return false;
        }
        else{
            return true;
        }
    }
}
